#pragma once 
#include <iostream>
#include <string>
#include <cassert>
#include <unordered_map>
#include <functional>
#include <ctime>

#include "tool.hpp"
#include "log.hpp"
#include "TcpServer.hpp"
#include "read_one_line.hpp"
#include "thread_pool.hpp"
#include "epoller.hpp" 

#define PORT 8080

class Connection;
class HttpServer;

using callback_t = std::function<void(Connection *)>;

// Connection 连接时长, 每次使用Connection刷新事件戳
const static int link_timeout = 10000 ; 
const static int max_ready_eventnums = 1000 ;   
const static int epoll_wait_timeout = 1000 ; 

class Connection
{
public:

    // 连接文件描述符
    int _fd ; 

    // string作为缓冲区有缺陷、不能接收二进制数据流
    // 未启用
    // 接收缓冲区
    std::string _inbuffer;
    // 输出缓冲区
    std::string _outbuffer;

    // 三种回调方法
    callback_t _recver;
    callback_t _sender;
    callback_t _excepter;

    // 用户信息  
    std::string _clientip;
    uint16_t _clientport;

    // epoll 关心该
    uint32_t _events ; 

    // 用设置Connect过期事件
    time_t  _last_ready_time  ; 

    // HttpServer回调指针
    HttpServer* r_call ; 
    
public:
    // 
    Connection(const int& fd, const std::string &clientip, const uint16_t &clientport)
    :_fd(fd)
    , _clientip(clientip)
    , _clientport(clientport)
    {

    }

    ~Connection()
    {

    }

    //注册回调函数
    void Register(callback_t recver, callback_t sender, callback_t excepter)
    {
        _recver = recver ; 
        _sender = sender ; 
        _excepter = excepter ; 
    }

    Connection(const int& fd) 
        :_fd(fd)
    {

    }

} ;
 



/* 
    uint16_t port_;
    Sock listensock_;
    Epoller epoller_;
    struct epoll_event revs_[gnum];
    func_t func_;
    std::unordered_map<int, Connection *> connections_;
*/


class HttpServer
{
private:

    // 接收epollwait就绪事件
    epoll_event _ready_events[max_ready_eventnums] ; 

    int _port ; 
    bool _stop ;

    TcpServer* _tser  ; 
    ThreadPool* _tp ;
    Epoller* _ep ;
    // fd 与 Connection 连接的映射表
    std::unordered_map<int, Connection *> _connections_hash;

public:

    HttpServer(int port = PORT)
        :_port(port)
        ,_stop(false)
    {

    }

    void initServer()
    {
       /*这段代码是用来忽略SIGPIPE信号的。
       SIGPIPE信号在网络编程中常见，它表示在读写socket时对方已经关闭连接，
       但继续读写会导致程序终止。通过调用signal(SIGPIPE, SIG_IGN)
       ，我们将SIGPIPE信号的处理方式设置为忽略，这样当出现SIGPIPE信号时，程序将不会终止，而是继续执行。*/

       // 可能有逻辑错误
        _tser = TcpServer::getinstance(_port); 
        _ep = Epoller::getInstance() ; 
        _tp = ThreadPool::getInstance(); 
        addConnection(_tser->get_sock(), EPOLLIN | EPOLLET);

        signal(SIGPIPE, SIG_IGN);
        LOG(INFO, "http_server init success") ;
    }

    void loop()
    {
        LOG(INFO, "loop begin") ;
        while (!_stop)
        {
            int n = _ep->epollWaitPacked(_ready_events, max_ready_eventnums, epoll_wait_timeout) ; 
            for(int i = 0; i < n; i++)
            {
                int fd = _ready_events[i].data.fd ; 
                uint32_t temp_event = _ready_events[i].events ; 
                std::string temp_message = std::to_string(fd) ; 
                LOG(INFO, "a connection will start use callback , which fd is ——" + temp_message) ; 

                  //将所有的异常情况全部转化成为recv，send的异常
                if((temp_event & EPOLLERR) || (temp_event & EPOLLHUP))
                {
                    temp_event |= (EPOLLIN | EPOLLOUT) ; 
                }

                if((temp_event & EPOLLIN) && adjustConnectionExite(fd))
                {
                    LOG(INFO, "a recver callback will be processed") ;
                    _connections_hash[fd]->_recver(_connections_hash[fd]) ;
                }
                if((temp_event & EPOLLOUT) && adjustConnectionExite(fd))
                {
                    _connections_hash[fd]->_sender(_connections_hash[fd]) ;
                }
            }

            //checkConntionsIsTimeout() ; 
        }
        
    }

    // 封装了epoll....add 
    void addConnection(int fd, uint32_t event, std::string ip = "127.0.0.1", uint16_t port = 8081)
    {
        // 如果_epfd为边缘触发模式则设置fd为非阻塞 
        if(event & EPOLLET)
        {
            if(Tool::SetNonBlock(fd) == false) 
            {
                LOG(WARNING, "have sock set nobolock failed") ; 
            }
        }

        Connection* new_con = new Connection(fd, ip, port) ; 

        if(fd == _tser->get_sock())
        {
            // 因为要用this指针调用HttpServer::accepter函数
            new_con->Register(std::bind(&HttpServer::accepterCallback, this, std::placeholders::_1), nullptr, nullptr );
        }
        else
        {
            new_con->Register(std::bind(&HttpServer::recverCallback, this, std::placeholders::_1), 
            std::bind(&HttpServer::senderCallback, this, std::placeholders::_1),
            std::bind(&HttpServer::excepterCallbck, this, std::placeholders::_1)) ; 
        }

        new_con->_events = event ; 
        new_con->r_call = this ; 
        new_con->_last_ready_time = time(nullptr) ; 
        _connections_hash[fd] = new_con ; 

        bool adjust = _ep->addEollEverntPacked(fd, event, EPOLL_CTL_ADD) ; 
        assert(adjust) ;
        // 防止优化 不执行 assert(adjust) ;
        (void) adjust ; 
        
        LOG(INFO, "add new Conmections success ") ;
    }


    // 监听客户端请求，建立新的Connection
    void accepterCallback(Connection* conn) 
    {
        do
        {
            int err =  0 ; 
            std::string clientip ; 
            uint16_t clientport ; 
            int sock = _tser->acceptPacked(&clientip, &clientport, &err) ; 
            if(sock > 0 )
            {
                std::string temp_message = clientip ; 
                LOG(INFO, temp_message + ": had connect") ;
                addConnection(sock, EPOLLIN | EPOLLET, clientip, clientport)  ; 
            }
            else
            {
                /*
                如果err等于EAGAIN，通常表示某个操作暂时不可用，应用程序可以重试该操作。
                如果err等于EWOULDBLOCK，通常表示该操作将阻塞调用进程，并建议稍后重试该操作
                */
                if( err == EAGAIN || err == EWOULDBLOCK)
                {
                    break; 
                }
                else if( err == EINTR)
                {
                    continue; 
                }
                else
                {
                    std::string temp_message = std::to_string(err) ; 
                    LOG(WARNING, "When accepte had error: " + temp_message);
                    continue; 
                }
            }
           
        } while (conn->_events & EPOLLET);
        
    }

    bool adjustConnectionExite(int fd)
    {
        if(_connections_hash.count(fd) == 1) 
        {
            return true ;
        }
        else
        {
            return false ; 
        }
    }

    void recverCallback(Connection* conn)
    {
        // 先不写入缓冲区直接调用线程池接取HTTP请求
        LOG(INFO, "a connetionc is processing which fd is" + std::to_string(conn->_fd)) ; 
        Task t(conn->_fd) ;
        _tp->pushTask(t) ; 
    }

    void senderCallback(Connection* conn)
    {
        // 未启用
        // 由于htpp响应只有在构筑好才能回复，如果将HttpProcessing的 构筑请求 + 发送应答拆分到
        // recverCallback和senderCallback两个函数中，则要将HttpDeamand的构造函数传擦改为传Connetion
        // 虽然完整发挥epoll模型作用，但增加了耦和等诸多不确定因素。
    }

    // 连接出现异常  // 释放Connection
    void excepterCallbck(Connection* conn)
    {
        
        _ep->deleteEpollEventPacked(conn->_fd) ; 

        _connections_hash.erase(conn->_fd) ; 
        
        // 原版本httpsend方法调用结束时似乎会释放, 所以记得将那里的close注释掉
        close(conn->_fd) ; 

        delete conn ; 

        std::string temp_message = std::to_string(conn->_fd) ; 
        temp_message += "  " ; 
        temp_message += std::to_string(time(nullptr)) ; 
        LOG(INFO, "a connections due to except close, which fd is " + temp_message) ; 
    }

    void checkConntionsIsTimeout()
    {
        for(pair<const int, Connection*>& it : _connections_hash)
        {
            time_t last_ready_time = it.second->_last_ready_time ; 

            // 不能把tcpserver的Connection给关了
            if((last_ready_time + link_timeout > time(nullptr))  && it.second->_fd != _tser->get_sock())
            {
                excepterCallbck(it.second) ; 
            }

        }

    }

};











